package weightPolling

import (
	"errors"
	"sort"
)

var slaveDns = map[int]map[string]interface{}{
	0: {"str": "a", "weight": 4},
	1: {"str": "b", "weight": 9},
	2: {"str": "c", "weight": 3},
}

var i int = -1  //表示上一次选择的服务器
var cw int = 0  //表示当前调度的权值
var gcd int = 1 //当前所有权重的最大公约数 比如 2，4，8 的最大公约数为：2

func GetDns() string {
	for {
		i = (i + 1) % len(slaveDns)
		if i == 0 {
			cw = cw - gcd
			if cw <= 0 {
				cw = getMaxWeight()
				if cw == 0 {
					return ""
				}
			}
		}

		if weight, _ := slaveDns[i]["weight"].(int); weight >= cw {
			return slaveDns[i]["str"].(string)
		}
	}
}

func getMaxWeight() int {
	max := 0
	for _, v := range slaveDns {
		if weight, _ := v["weight"].(int); weight >= max {
			max = weight
		}
	}

	return max
}

type weightPolicy struct {
	weightMap             map[int]int
	number                int
	maxWeight             int
	greatestCommonDivisor int
	currentWeight         int
	step                  int
}

var policy weightPolicy

//moreArg 提供参与计算的数量,最大权重值，最大公约数，若没有同时提供则自行计算。
func NewWeightPolicy(weightMaps map[int]int, execArg ...int) (weightPolicyEntity weightPolicy, err error) {
	if weightMaps == nil {
		err = errors.New("not init map")
		return
	}
	policy = weightPolicy{}
	policy.weightMap = weightMaps
	if len(execArg) != 3 {
		policy.number, policy.maxWeight, policy.greatestCommonDivisor = policy.GetExecArg()
	}
	policy.step, policy.currentWeight = -1, 0
	weightPolicyEntity = policy
	return
}

func (m weightPolicy) GetExecArg() (number int, max int, gcd int) {
	list := []int{}
	for _, v := range m.weightMap {
		list = append(list, v)
	}
	sort.Ints(list)
	number = len(list)
	max = list[len(list)-1]
	gcd = getGcd(list)
	return
}

func getGcd(list []int) int {
	first := list[0]
	second := list[1]
	gcd := greatestCommonDivisor(first, second)
	for k, v := range list {
		if k == 0 || k == 1 {
			continue
		}
		gcd = greatestCommonDivisor(v, gcd)
	}
	return gcd
}

func greatestCommonDivisor(a, b int) int {
	if a < b {
		a, b = b, a
	}
	for {
		r := a % b
		if r == 0 {
			return b
		}
		a, b = b, r
	}
}

/*func (m weightPolicy) GetIndex() (w, i int) {
	for {
		m.step++
		m.step = m.step % m.number
		fmt.Println(m.step, m.currentWeight)
		if m.step == 0 {
			m.currentWeight = m.currentWeight - m.greatestCommonDivisor
			if m.currentWeight <= 0 {
				m.currentWeight = m.maxWeight
			}
		}
		if m.weightMap[m.step] >= m.currentWeight {
			return m.weightMap[m.step], m.step
		}
	}
}*/

func (m *weightPolicy) GetIndex() (w, i int) {
	for {
		m.step++
		m.step = m.step % m.number
		if m.step == 0 {
			m.currentWeight = m.currentWeight - m.greatestCommonDivisor
			if m.currentWeight <= 0 {
				m.currentWeight = m.maxWeight
			}
		}
		if m.weightMap[m.step] >= m.currentWeight {
			return m.weightMap[m.step], m.step
		}
	}
}
